package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.feign.clients.ArticleClient;
import com.heima.feign.clients.ScheduleClient;
import com.heima.model.article.dtos.SaveArticleDto;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.enums.TaskTypeEnum;
import com.heima.model.common.enums.WmNewsMessageConstants;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.wemedia.dtos.*;
import com.heima.model.wemedia.pojos.*;
import com.heima.model.wemedia.vos.WmNewsAuthVo;
import com.heima.utils.common.ProtostuffUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.*;
import com.heima.wemedia.uitls.ThreadLocalUtils;
import io.protostuff.ProtostuffIOUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements IWmNewsService {
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private IWmMaterialService wmMaterialService;
    @Autowired
    private IWmNewsAutoScanService wmNewsAutoScanService;
    @Autowired
    private ScheduleClient scheduleClient;
    @Autowired
    private IWmNewsToTaskService wmNewsToTaskService;
    @Autowired
    private IWmUserService wmUserService;
    @Autowired
    private ArticleClient articleClient;
    @Autowired
    private IWmChannelService wmChannelService;
    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    /**
     * 文章查询
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageDto dto) {
        //校验参数是否存在
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //校验当前用户是否登录
        if (ThreadLocalUtils.getUser() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //构造分页查询条件
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //构造条件查询条件
        QueryWrapper<WmNews> queryWrapper = new QueryWrapper<>();
        //校验请求参数中是否包含开始时间和结束时间
        if (dto.getBeginPubdate() != null && dto.getEndPubdate() != null) {
            //构造时间条件
            queryWrapper.between("publish_time", dto.getBeginPubdate(), dto.getEndPubdate());
        }
        //校验请求参数中频道Id是否存在
        if (dto.getChannelId() != null) {
            //构造频道查询条件
            queryWrapper.eq("channel_id", dto.getChannelId());
        }
        //校验请求参数中的关键字查询参数是否存在
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            //构造关键字模糊查询条件
            queryWrapper.like("title", dto.getKeyword());
        }
        //校验请求参数中的status状态是否存在
        if (dto.getStatus() != null) {
            queryWrapper.eq("status", dto.getStatus());
        }
        //根据当前用户进行查询
        queryWrapper.eq("user_id", ThreadLocalUtils.getUser().getId());
        //按照创建时间倒序排列
        queryWrapper.orderByDesc("created_time");
        //调用分页查询方法进行查询
        Page<WmNews> pageInfo = this.page(page, queryWrapper);
        //封装分页查询结果
        PageResponseResult responseResult = new PageResponseResult();
        responseResult.setCurrentPage(dto.getPage());
        responseResult.setSize(dto.getSize());
        responseResult.setTotal((int) pageInfo.getTotal());
        responseResult.setData(pageInfo.getRecords());
        return responseResult;
    }

    /**
     * 文章发布和保存草稿
     * status  0  保存草稿
     * status  1  发布文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //校验请求参数中图文数据content是否为空
        if (dto.getContent() == null) {
            //为空则直接返回,不能进行添加操作
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //判断请求参数中的type属性的值,当为-1时,因为wmNews中type的值不能为-1,则需要把type的值设置为null
        if (dto.getType() == -1) {
            dto.setType(null);
        }
        //向图文数据表中添加一条数据,创建一个图文数据对象
        WmNews wmNews = new WmNews();
        //将请求参数中的数据拷贝到图文对象中
        BeanUtils.copyProperties(dto, wmNews);
        //将其他属性值补全
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setUserId(ThreadLocalUtils.getUser().getId());
        /*取出图文数据中的图片信息,封装到list集合中,后续需要根据图片数据去查询对应的图文素材id
        同时,当请求参数中的type= -1 时,封面图片需要从图文数据中取出图片进行添加*/
        //取出图文数据中的图片信息,新建一个list集合用于封装数据

        List<String> imagesList = new ArrayList<>(); //存放的文章中的素材地址
        String content = wmNews.getContent();
        //将字符串转换为list集合,集合中的元素为map集合
        List<Map> maps = JSON.parseArray(content, Map.class);
        //遍历集合,从结合中的每一个map获取到type为image的value值,封装到list集合中
        for (Map map : maps) {
            if (map.get("type").equals("image")) {
                String value = (String) map.get("value");
                //将value存入list结合中
                imagesList.add(value);
            }
        }
        //获取请求参数中的封面图片数据集合,对其进行相关操作,将元素之间用逗号分隔开

        List<String> images = dto.getImages(); //存放的封面中的素材地址

        //对封面图片类型进行判断,type为-1时,需要从imagesList取出对应的图片加上逗号拼接后存储,实现自动添加图片
        //判断imagesList集合的长度,来决定应该采用哪种自动展示封面图片的策略
        if (dto.getType() == null) {
            //当图文数据中图片数量大于等于1   小于3时  单图
            if (imagesList.size() >= 1 && imagesList.size() < 3) {
                images = imagesList.stream().limit(1).collect(Collectors.toList());
                wmNews.setType((short) 1);
            }
            //当图文数据中图片数量大于等于3时  三图
            if (imagesList.size() >= 3) {
                images = imagesList.stream().limit(3).collect(Collectors.toList());
                wmNews.setType((short) 3);
            }
            //当图文数据中图片数量小于1时  无图
            if (imagesList.size() < 1) {
                wmNews.setType((short) 0);
            }
        }
        //封面图片状态type为其他值时,需要将请求参数中的images取出拼接逗号后进行存储
        wmNews.setImages(StringUtils.join(images, ","));
        //至此,将数据库中需要存入的images属性封装完毕,图文数据表数据也封装完整了,调用方法进行存储即可
        //判断请求参数中是否有id这个参数
        if (dto.getId() != null) {
            //有id属性则执行修改操作,将文章素材关系表中的数据根据文章id进行删除,构造删除条件
            QueryWrapper<WmNewsMaterial> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("news_id", dto.getId());
            wmNewsMaterialMapper.delete(queryWrapper);
            //调用方法,修改图文数据表中的信息
            this.updateById(wmNews);
        } else {
            //无id属性则执行新增操作
            this.save(wmNews);
        }
        //判断请求参数中的status状态值, 0表示保存草稿,  1表示提交审核
        if (wmNews.getStatus() == 0) {
            //如果是保存草稿,则不需要向文章素材表中添加数据,到此结束
            return ResponseResult.okResult(200, "保存成功");
        }

        //操作完了图文数据表之后,需要在文章素材关联表中添加对应的信息
        //imagesList中封装的文章中的图片地址集合 type = 0    images中封装的是封面图片地址集合 type = 1
        //先将图文数据中的素材与文章关系存到中间表中
        //创建一个list集合封装文章中的素材id
        List<Integer> materialIds1 = new ArrayList<>();
        if (imagesList != null && imagesList.size() > 0) {
            //根据素材路径去素材表中查询对应的素材对象,并获取素材id,构造查询条件
            QueryWrapper<WmMaterial> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("url", imagesList);
            List<WmMaterial> wmMaterials = wmMaterialService.list(queryWrapper);
            for (WmMaterial wmMaterial : wmMaterials) {
                //将素材id存入集合中
                materialIds1.add(wmMaterial.getId());
            }
            //调用mapper层方法,执行添加操作
            wmNewsMaterialMapper.saveNewsAndMaterial(materialIds1, wmNews.getId(), (short) 0);
        }

        //再将封面数据中的素材与文章关系存到中间表中
        //创建一个list集合封装文章中的素材id
        List<Integer> materialIds2 = new ArrayList<>();
        if (images != null && images.size() > 0) {
            //根据素材路径去素材表中查询对应的素材对象,并获取素材id,构造查询条件
            QueryWrapper<WmMaterial> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("url", images);
            List<WmMaterial> wmMaterials = wmMaterialService.list(queryWrapper);
            for (WmMaterial wmMaterial : wmMaterials) {
                //将素材id存入集合中
                materialIds2.add(wmMaterial.getId());
            }
            //调用mapper层方法,执行添加操作
            wmNewsMaterialMapper.saveNewsAndMaterial(materialIds2, wmNews.getId(), (short) 1);
        }

        /*//执行文章内容审核
        wmNewsAutoScanService.AutoScanTextAndImages(wmNews.getId());*/
        //远程调用发布任务接口
        wmNewsToTaskService.addNewsToTask(wmNews.getId(), wmNews.getPublishTime());

        return ResponseResult.okResult(200, "操作成功");
    }

    /**
     * 根据id查询文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findById(Integer id) {
        //校验请求参数是否存在
        if (id == null) {
            //返回错误状态码,数据不存在
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //调用方法,执行根据id查询的操作
        WmNews wmNews = this.getById(id);
        return ResponseResult.okResult(wmNews);
    }

    /**
     * 根据id删除文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteById(Integer id) {
        //校验参数
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id去数据库中查询数据,不能查询到则返回错误状态码,数据库中无数据
        WmNews wmNews = this.getById(id);
        if (wmNews == null) {
            //响应错误状态码
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //如果能查询到,则判断此文章数据的状态status是否是已发布
        if (wmNews.getStatus() == 9) {
            return ResponseResult.errorResult(501, "文章已发布,不能删除");
        }
        //调用方法,执行删除操作,先删除文章素材关系表中的相关数据
        //构造删除条件
        QueryWrapper<WmNewsMaterial> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("news_id", id);
        wmNewsMaterialMapper.delete(queryWrapper);
        //删除完毕后,再调方法删除文章表中的数据
        this.removeById(id);
        return ResponseResult.okResult(200, "操作成功");
    }

    /**
     * 上下架
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult DownOrUp(WmNewsDownOrUpDto dto) {
        //校验请求参数中id是否存在
        if (dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //校验请求参数中enable是否存在
        if (dto.getEnable() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //根据id去数据库中查询相应的数据
        WmNews wmNews = this.getById(dto.getId());
        //判断查询到的对象是否为空
        if (wmNews == null) {
            //为空,则返回错误状态码
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //对象不为空,则需要判断对象的status状态值是否为发布状态
        if (wmNews.getStatus() != 9) {
            //文章不是发布状态不能上下架
            return ResponseResult.errorResult(501, "当前文章不是发布状态,不能上下架");
        }
        //对象状态为发布状态,则将对象的enable属性值修改为请求参数中的上下架状态值
        wmNews.setEnable(dto.getEnable());
        //调用方法,执行修改操作
        this.updateById(wmNews);
        //通过kafka发送消息,修改APP端的文章配置,查询出来的对象中需要有articleId这份属性
        if(wmNews.getArticleId() !=null){
            //将需要发送的消息内容封装为一个map
            Map<String,Object> map =new HashMap<>();
            map.put("articleId",wmNews.getArticleId());
            map.put("enable",dto.getEnable());
            //发送消息
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(map));
        }

        return ResponseResult.okResult(200, "操作成功");
    }

    /**
     * 后台管理端--查询文章列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult listVo(WmNewsAuthDto dto) {
        //校验请求参数是否存在
        if (dto.getPage() == null || dto.getSize() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //构造分页查询条件
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //构造条件查询条件
        QueryWrapper<WmNews> queryWrapper = new QueryWrapper<>();
        //判断有无title参数,有则需要模糊查询
        if (dto.getTitle() != null) {
            queryWrapper.like("title", dto.getTitle());
        }
        //判断有无审核状态
        if (dto.getStatus() != null) {
            queryWrapper.eq("status", dto.getStatus());
        }
        //根据创建时间倒序查询
        queryWrapper.orderByDesc("created_time");
        //调用方法执行查询
        Page<WmNews> pageInfo = this.page(page, queryWrapper);
        //获取查询出来的数据,给每一个数据设置一个创作人姓名属性值
        List<WmNews> records = pageInfo.getRecords();
        //创建一个新的集合用于封装返回数据
        List<WmNewsAuthVo> list = new ArrayList<>();
        //遍历集合,将每一个wmNews对象的属性值拷贝到wmNewsAuthVo上,并设置作者名字属性
        for (WmNews record : records) {
            //创建vo对象
            WmNewsAuthVo wmNewsAuthVo = new WmNewsAuthVo();
            BeanUtils.copyProperties(record, wmNewsAuthVo);
            //根据作者id查询作者名字再进行封装
            Integer userId = record.getUserId();
            WmUser wmUser = wmUserService.getById(userId);
            wmNewsAuthVo.setAuthorName(wmUser.getName());
            //将数据存储到集合中
            list.add(wmNewsAuthVo);
        }
        //封装结果集
        PageResponseResult responseResult = new PageResponseResult();
        responseResult.setData(list);
        responseResult.setTotal((int) pageInfo.getTotal());
        responseResult.setSize(dto.getSize());
        responseResult.setCurrentPage(dto.getPage());
        return responseResult;
    }

    /**
     * 后台管理端查询文章详情
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult oneVo(Integer id) {
        //校验请求参数是否存在
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id去文章表中查询数据
        WmNews wmNews = this.getById(id);
        //判断查询出来的数据是否为空
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //封装结果集,创建一个vo对象,拷贝属性值,并补全作者姓名属性
        WmNewsAuthVo wmNewsAuthVo = new WmNewsAuthVo();
        BeanUtils.copyProperties(wmNews, wmNewsAuthVo);
        //查询文章作者姓名
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        wmNewsAuthVo.setAuthorName(wmUser.getName());
        //将对象返回
        return ResponseResult.okResult(wmNewsAuthVo);
    }

    /**
     * 后台管理---文章审核---审核通过
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult authPass(WmNewsAuthPassOrFailDto dto) {
        //校验请求参数是否存在
        if (dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //id存在,则根据id查询wmNews表
        WmNews wmNews = this.getById(dto.getId());
        //判断是否查询出了数据
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //判断查询结果的status是否为3
        if (wmNews.getStatus() != 3) {
            return ResponseResult.errorResult(501, "文章不需要人工审核");
        }
        //确定文章需要人工审核,远程调用保存文章三剑客方法
        SaveArticleDto saveArticleDto = saveWmNewsToArticle(wmNews);

        ResponseResult responseResult = articleClient.saveArticle3(saveArticleDto);
        //对响应参数中的状态码进行判断
        if (!responseResult.getCode().equals(200)){
            return ResponseResult.errorResult(501,"APP端新增文章错误");
        }
        //状态值为200,说明新增成功,需要修改文章审核状态,回填app端文章id
        wmNews.setStatus((short) 9);
        wmNews.setReason("审核成功");
        wmNews.setArticleId((Long) responseResult.getData());
        //调用方法执行修改操作
        this.updateById(wmNews);
        return ResponseResult.okResult(200,"操作成功");
    }

    /**
     * 封装保存文章三剑客的请求参数
     *
     * @param wmNews
     * @return
     */
    private SaveArticleDto saveWmNewsToArticle(WmNews wmNews) {
        //封装请求参数,创建请求参数对象
        SaveArticleDto saveArticleDto = new SaveArticleDto();
        //将相同的属性进行拷贝
        BeanUtils.copyProperties(wmNews, saveArticleDto);
        //补全作者id和作者姓名
        if (wmNews.getUserId() != null) {
            saveArticleDto.setAuthorId(wmNews.getUserId().longValue());
            //根据作者id去查询作者姓名
            WmUser wmUser = wmUserService.getById(wmNews.getUserId());
            if (wmUser != null) {
                saveArticleDto.setAuthorName(wmUser.getName());
            }
        }
        //补全频道名称
        if (wmNews.getChannelId() != null) {
            //根据频道id查询频道表获取频道名称
            WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
            if (wmChannel != null) {
                saveArticleDto.setChannelName(wmChannel.getName());
            }
        }
        //补全文章布局属性
        if (wmNews.getType() != null) {
            saveArticleDto.setLayout(wmNews.getType());
        }
        //补全库文章id属性
        if (wmNews.getArticleId() != null) {
            saveArticleDto.setId(wmNews.getArticleId());
        }
        //设置创建时间
        saveArticleDto.setCreatedTime(new Date());
        return saveArticleDto;
    }

    /**
     * 后台管理,文章审核---审核失败
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult authFail(WmNewsAuthPassOrFailDto dto) {
        //校验请求参数是否存在
        if (dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //id存在,则根据id查询wmNews表
        WmNews wmNews = this.getById(dto.getId());
        //判断是否查询出了数据
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //判断查询结果的status是否为3
        if (wmNews.getStatus() != 3) {
            return ResponseResult.errorResult(501, "文章不需要人工审核");
        }
        //确定需要人工审核,则修改审核状态为审核失败
        wmNews.setStatus((short) 2);
        wmNews.setReason(dto.getMsg());
        this.updateById(wmNews);
        return ResponseResult.okResult(200, "操作成功");
    }
}
